﻿
using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Diagnostics;
using System.IO;
using System.Linq;
using System.Xml;
using System.Xml.Serialization;
using Bugzproxy;
using Styx;
using Styx.Helpers;
using Styx.Logic.Combat;
using Styx.WoWInternals;
using Styx.WoWInternals.WoWObjects;

namespace Altarboy
{
  static class TargetManager
    {

        // Current Player   
        public static LocalPlayer Me { get { return StyxWoW.Me; }}

        #region Add Detection
     
        public static List<WoWUnit> DetectHostileTargets(int range)
        {
            var addList = ObjectManager.GetObjectsOfType<WoWUnit>(false).FindAll(unit =>
                        unit.Guid != Me.Guid &&
                        unit.Distance <= range &&
                        ShouldAttack(unit))
                        .OrderBy(unit => unit.CurrentHealth).ToList();
            return addList;
        }
        #endregion
                
        public static bool IsUnitInRange(WoWUnit unit, double range)
        {
            return (unit != null && unit.Distance < range && unit.InLineOfSightOCD);
        }

        public static bool ShouldAttack(WoWUnit unit)
        {
            if (unit.Name == "Training Dummy" || unit.Name == "Raider's Training Dummy")
            {
                return true;
            }
            return unit.Attackable
                   && !IsCrowdControlled(unit)
                   && unit.IsAlive
                   && unit.Combat
                   && (!unit.IsPlayer || unit.ToPlayer().IsHorde != Me.IsHorde)
                   && !IsMeOrMyGroup(unit)
                   && (IsTargetingMeOrMyGroup(unit) || unit.CreatureType == WoWCreatureType.Totem)
                   && !Styx.Logic.Blacklist.Contains(unit.Guid)
                   && !TargetManager.IsIgnoreTarget(unit);
        }

      public static int NumOfHostileWithinRange(WoWUnit target, double range) { 

             var mobList = (from o in ObjectManager.ObjectList
                                   where o is WoWUnit && o.Distance <= 50
                                   let unit = o.ToUnit()
                                   where ShouldAttack(unit)
                                   select unit
                                    ).ToList();
          return mobList.Count(unit => target.Location.Distance(unit.Location) <= range);
        }

      public static bool CrowdControllUnitInRange(WoWUnit target, double range)
      {
          var mobList = (from o in ObjectManager.ObjectList
                         where o is WoWUnit && o.Distance <= 50
                         let unit = o.ToUnit()
                         where unit.IsAlive
                         select unit
                        ).ToList();
          return mobList.Any(unit => IsCrowdControlled(unit) && target.Location.Distance(unit.Location) <= range);
      }

      public static bool IsCrowdControlled(WoWUnit unit)
      {
          return unit.GetAllAuras().Any(
              a => a.IsHarmful &&
                   (a.Spell.Mechanic == WoWSpellMechanic.Shackled ||
                    a.Spell.Mechanic == WoWSpellMechanic.Polymorphed ||
                    a.Spell.Mechanic == WoWSpellMechanic.Horrified ||
                    a.Spell.Mechanic == WoWSpellMechanic.Rooted ||
                    a.Spell.Mechanic == WoWSpellMechanic.Frozen ||
                    a.Spell.Mechanic == WoWSpellMechanic.Stunned ||
                    a.Spell.Mechanic == WoWSpellMechanic.Fleeing ||
                    a.Spell.Mechanic == WoWSpellMechanic.Banished ||
                    a.Spell.Mechanic == WoWSpellMechanic.Sapped));
      }

        public static bool IsMeOrMyStuff(WoWUnit unit)
        {
            if (unit == null)
                return false;

            // find topmost unit in CreatedByUnit chain
            while (unit.CreatedByUnit != null)
                unit = unit.CreatedByUnit;

            // check if this unit was created by me
            return unit.IsMe;
        }

        public static bool IsTargetingMeOrMyStuff(WoWUnit unit)
        {
            return unit != null && IsMeOrMyStuff(unit.CurrentTarget);
        }

        public static bool IsMeOrMyGroup(WoWUnit unit)
        {
            if (unit != null)
            {
                // find topmost unit in CreatedByUnit chain
                while (unit.CreatedByUnit != null)
                    unit = unit.CreatedByUnit;

                if (unit.IsMe)
                    return true;

                if (unit.IsPlayer)
                {
                    WoWPlayer p = unit.ToPlayer();
                    if (p.IsHorde == Me.IsHorde && PartyManager.GroupMembers.Contains(unit.ToPlayer()))
                        return true;
                }
            }

            return false;
        }

        public static bool IsTargetingMeOrMyGroup(WoWUnit unit)
        {
            return unit != null && IsMeOrMyGroup(unit.CurrentTarget);
        }


        public enum RaidTargetIcon
        {
            None = 0,
            Star = 1,
            Circle = 2,
            Diamond = 3,
            Triangle = 4,
            Moon = 5,
            Square = 6,
            Cross = 7,
            Skull = 8,
        }
        
       
        //public static void SetRaidTarget(this WoWUnit unit, RaidTargetIcon icon)
        //{
        //    WoWUnit currentTarget = StyxWoW.Me.CurrentTarget;
        //    unit.Target();
        //    Lua.DoString("SetRaidTarget(\"target\", {0});", (int)icon);
        //    currentTarget.Target();
        //}

        public static RaidTargetIcon GetRaidTarget(this WoWUnit unit)
        {
         
            //this is slow as fuck... right now it has to manually target each unit to check it.
            WoWUnit currentTarget = StyxWoW.Me.CurrentTarget;
            unit.Target();
            var icon = Lua.GetReturnVal<int>("return GetRaidTargetIndex(\"target\");", 0);
            currentTarget.Target();

            return icon > 8 || icon < 0 ? RaidTargetIcon.None : (RaidTargetIcon) icon;
        }

        public static Boolean EnemyHasRaidMarker(WoWUnit unit, RaidTargetIcon raidMarker)
        {
            return ShouldAttack(unit) && GetRaidTarget(unit) == raidMarker;
        }


        private static BindingList<SpecialTarget> _AltarboySpecialTargets;
        public static BindingList<SpecialTarget> AltarboySpecialTargets
        {
            get
            {
                if(_AltarboySpecialTargets == null )
                {
                    string sPath = Process.GetCurrentProcess().MainModule.FileName;
                    sPath = Path.GetDirectoryName(sPath) + "/CustomClasses/Altarboy/utils/SpecialTargets.xml";

                    if (File.Exists(sPath))
                     {
                         var serializer = new XmlSerializer(typeof(BindingList<SpecialTarget>));
                         StreamReader reader = new StreamReader(sPath);
                         _AltarboySpecialTargets = (BindingList<SpecialTarget>)serializer.Deserialize(reader);

                     } else
                     {
                         _AltarboySpecialTargets = new BindingList<SpecialTarget>();
                     }
                }
                return _AltarboySpecialTargets;
            }
            set { _AltarboySpecialTargets = value; }
        }

      public static void SaveSpecialTargets()
      {
          if (_AltarboySpecialTargets != null)
          {
              string sPath = Process.GetCurrentProcess().MainModule.FileName;
              sPath = Path.GetDirectoryName(sPath) + "/CustomClasses/Altarboy/utils/SpecialTargets.xml";
              XmlSerializer serializer = new XmlSerializer(typeof (BindingList<SpecialTarget>));
              TextWriter tw = new StreamWriter(sPath);
              serializer.Serialize(tw, _AltarboySpecialTargets);
              tw.Close();
          }
      }

      public static bool IsSpecialTarget(WoWUnit unit)
      {
          return AltarboySpecialTargets.Any(u => u.TargetId == unit.Entry);
      }

      public static bool IsFocusTarget(WoWUnit unit)
      {
          return AltarboySpecialTargets.Any(u => u.TargetId == unit.Entry && u.Focus ) ;
      }

      public static bool IsIgnoreTarget(WoWUnit unit)
      {
          return AltarboySpecialTargets.Any(u => u.TargetId == unit.Entry && u.Ignore);
      }

      public static bool IsMindSpikeTarget(WoWUnit unit)
      {
          return AltarboySpecialTargets.Any(u => u.TargetId == unit.Entry && u.MindSpike );
      }
      public static bool IsMindSearTarget(WoWUnit unit)
      {
          return AltarboySpecialTargets.Any(u => u.TargetId == unit.Entry && u.MindSear);
      }

      public static bool IsUnsafeShadowWordDeath(WoWUnit unit)
      {
          return AltarboySpecialTargets.Any(u => u.TargetId == unit.Entry && u.UnsafeSWD);
      }

    }
  
    [Serializable()]  
   public class SpecialTarget
    {
        public uint TargetId { get; set; }
        public string TargetName { get; set; }
        public bool Focus { get; set; }
        public bool Ignore { get; set; }
        public bool MindSpike { get; set; }
        public bool MindSear { get; set; }
        public bool UnsafeSWD { get; set; }
    }
    

}

